use super::{
    err, err_value, json, ok, throw_err, Base, ECode, Fbf, Lock, Resp, SvCache, VBase, VMap, Value,
};

pub struct FileDb;

impl Base for FileDb {}

impl FileDb {
    pub async fn do_cmd(
        &self,
        para: &Value,
        cmd: &str,
        k: &str,
        cache: SvCache,
        lock: Lock,
    ) -> Resp {
        let reader = Fbf;
        let data = para.ckobj()?;

        let line = data.ck_str("line")?;

        match cmd {
            "get" => {
                let _ = lock.lock().await;

                let sn = data.ck_str("sn")?;
                let body = reader.get_file(line, "file", k, &cache)?;
                let body = body.ck_obj(sn)?;

                ok!(body)
            }
            "read" => {
                let _ = lock.lock().await;
                let body = reader.get_file(line, "file", k, &cache)?;

                ok!(body)
            }
            "exist" => {
                let _ = lock.lock().await;
                let ret = reader.is_exist(line, "file", k)?;

                ok!(ret)
            }
            "list" => {
                let _ = lock.lock().await;

                let mut body = reader.get_file(line, "file", k, &cache)?;
                let body = body.ckobj_mut()?;

                let mut ret = vec![];

                for (k, v) in body.iter_mut() {
                    match v.kobj_mut() {
                        Some(t) => {
                            t.insert("sn".to_string(), json!(k));
                            ret.push(json!(t));
                        }
                        None => {
                            ret.push(json!(v));
                        }
                    }
                }

                ok!(ret)
            }
            "modify" => {
                let _ = lock.lock().await;
                let item = data.ck_obj("v")?;

                match reader.get_file(line, "file", k, &cache) {
                    Ok(mut body) => {
                        let body = body.ckobj_mut()?;

                        for (sn, val) in item.iter() {
                            let val = val.ckobj()?;

                            match body.k_obj_mut(sn) {
                                Some(tmp) => {
                                    for (k, v) in val.iter() {
                                        tmp.insert(k.to_string(), v.clone());
                                    }
                                }
                                None => {
                                    body.insert(sn.to_string(), json!(val));
                                }
                            }
                        } // for

                        let body = json!(body);
                        reader.write(line, "file", k, &body, &cache).await?;
                    }
                    Err(_) => {
                        let body = json!(item);
                        reader.write(line, "file", k, &body, &cache).await?;
                    }
                }

                ok!()
            }
            "md" => {
                let _ = lock.lock().await;

                let item = data.ck_obj("v")?;
                let sn = data.ck_str("sn")?;

                if let Some(new_sn) = item.k_str("sn") {
                    if sn != new_sn {
                        throw_err!(ECode::Para, "sn not the same");
                    }
                }

                match reader.get_file(line, "file", k, &cache) {
                    Ok(mut body) => {
                        let body = body.ckobj_mut()?;

                        match body.k_obj_mut(sn) {
                            Some(tmp) => {
                                for (k, v) in item.iter() {
                                    tmp.insert(k.to_string(), v.clone());
                                }
                            }
                            None => {
                                body.insert(sn.to_string(), json!(item));
                            }
                        }

                        let body = json!(body);
                        reader.write(line, "file", k, &body, &cache).await?;
                    }
                    Err(_) => {
                        let body = json!({sn: item});
                        reader.write(line, "file", k, &body, &cache).await?;
                    }
                }

                ok!()
            }
            "rmfile" => {
                let _ = lock.lock().await;
                let _ = reader.remove(line, "file", k, &cache).await?;

                ok!()
            }
            "rmset" => {
                let _ = lock.lock().await;

                let val = data.ck_array("v")?;

                if let Ok(mut body) = reader.get_file(line, "file", k, &cache) {
                    let body = body.ckobj_mut()?;

                    for d in val.iter() {
                        let sn = d.ck_str("sn")?;
                        body.remove(sn);
                    }

                    if body.is_empty() {
                        let _ = reader.remove(line, "file", k, &cache).await?;
                    } else {
                        let body = json!(body);
                        let _ = reader.write(line, "file", k, &body, &cache).await?;
                    }
                }

                ok!()
            }
            "rm" => {
                let _ = lock.lock().await;

                let sn = data.ck_str("sn")?;

                if let Ok(mut body) = reader.get_file(line, "file", k, &cache) {
                    let body = body.ckobj_mut()?;
                    body.remove(sn);

                    if body.is_empty() {
                        let _ = reader.remove(line, "file", k, &cache).await?;
                    } else {
                        let body = json!(body);
                        let _ = reader.write(line, "file", k, &body, &cache).await?;
                    }
                }

                ok!()
            }
            _ => throw_err!(ECode::NoServe, "no file serve"),
        }
    }
}
